using System;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using PasteCodeTaskBase;
using Volo.Abp;
using Volo.Abp.Autofac;
using Volo.Abp.Json;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle;

namespace PasteTimer
{
    /// <summary>
    /// 
    /// </summary>
    [DependsOn(
        typeof(PasteTimerApplicationModule),
        typeof(PasteTimerEntityFrameworkCoreModule),
        typeof(AbpAutofacModule),
        typeof(AbpSwashbuckleModule)
        )]
    public class PasteTimerHttpApiHostModule : AbpModule
    {
        private const string DefaultCorsPolicyName = "Default";

        //private static bool debug = false;

        //private static IConfigurationRoot configuartion = null;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        public override void ConfigureServices(ServiceConfigurationContext context)
        {

            var hostingEnvironment = context.Services.GetHostingEnvironment();
            var Configuration = context.Services.GetConfiguration();

            //重复了
            //context.Services.AddSingleton<IConfiguration>(Configuration);

            //context.Services.Configure<OptionConnectionConfig>(Configuration.GetSection("ConnectionStrings"));//abc:abcitem
            context.Services.Configure<RedisConfig>(Configuration.GetSection("RedisConfig"));//abc:abcitem
            context.Services.Configure<TaskConfig>(Configuration.GetSection("TaskConfig"));
            context.Services.AddSingleton<IAppCache, AppRedis>();
            //载入第一个

            //context.Services.AddAbpDbContext<PasteTimerDbContext>(op =>
            //{
            //    Configure<AbpDbContextOptions>(aa => { aa.UseNpgsql(); });
            //});

            context.Services.AddHttpClient();

            //.net6 处理 设置启用时区时间
            //AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
            //AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
            //处理 The request was canceled due to the configured HttpClient.Timeout of 10 seconds elapsing. 异常
            //AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);

            context.Services.Configure<Volo.Abp.AspNetCore.Mvc.AbpAspNetCoreMvcOptions>(options =>
            {
                options.ConventionalControllers.Create(typeof(PasteTimerApplicationModule).Assembly, optio =>
                {
                    optio.UseV3UrlStyle = true;
                    optio.RootPath = "task";
                });
            });

            context.Services.AddAbpSwaggerGen(
                options =>
                {
                    //Bearer
                    options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
                    {
                        Name = "token",
                        Scheme = "",
                        Description = "在此输入token信息",
                        In = ParameterLocation.Header,
                        Type = SecuritySchemeType.ApiKey
                    });
                    //options.AddSecurityDefinition
                    //options.OperationFilter<AddAuthTokenHeaderParameter>();

                    //添加文档
                    options.SwaggerDoc("v1", new OpenApiInfo { Title = "Support APP API", Version = "v1" });
                    options.DocInclusionPredicate((docName, description) =>
                    {
                        if (description.RelativePath.Contains("/tick/") || description.RelativePath.Contains("/task/") || description.RelativePath.Contains("/slave/"))
                        {
                            return true;
                        }
                        else
                        {
                            return false;
                        }
                    });
                    options.CustomSchemaIds(type => type.FullName);
                    //添加小锁
                    options.AddSecurityRequirement(new OpenApiSecurityRequirement() {
                       {new OpenApiSecurityScheme{ Reference=new OpenApiReference{ Type=ReferenceType.SecurityScheme,Id="Bearer" }},new string[]{ }}
                    });

                    //重复的时候，使用第一个
                    options.ResolveConflictingActions(apidesc => apidesc.First());

                    //这里可以用isdevmodel来判断
                    if (System.IO.File.Exists(@"PasteTimer.Application.xml")) { options.IncludeXmlComments(@"PasteTimer.Application.xml"); }
                    if (System.IO.File.Exists(@"PasteTimer.Application.Contracts.xml")) { options.IncludeXmlComments(@"PasteTimer.Application.Contracts.xml"); }
                    if (System.IO.File.Exists(@"PasteTimer.Domain.xml")) { options.IncludeXmlComments(@"PasteTimer.Domain.xml"); }
                    if (System.IO.File.Exists(@"PasteTimer.HttpApi.Host.xml")) { options.IncludeXmlComments(@"PasteTimer.HttpApi.Host.xml"); }
                    //添加模块介绍
                    options.DocumentFilter<AuthTagDescriptions>();
                }
            );

            //context.Services.AddSwaggerGenNewtonsoftSupport();

            //全局处理异常信息
            context.Services.AddControllers(options => { options.Filters.Add(typeof(TaskExceptionAttribute)); });

            context.Services.AddCors(options =>
            {
                options.AddPolicy(DefaultCorsPolicyName, builder =>
                {
                    builder
                        .WithOrigins(
                            Configuration["App:CorsOrigins"]
                                .Split(",", StringSplitOptions.RemoveEmptyEntries)
                                .Select(o => o.RemovePostFix("/"))
                                .ToArray()
                        )
                        .WithAbpExposedHeaders()
                        .SetIsOriginAllowedToAllowWildcardSubdomains()
                        .AllowAnyHeader()
                        .AllowAnyMethod()
                        .AllowCredentials();
                });
            });

            var dev = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
            if (!String.IsNullOrEmpty(dev) && dev == "Development")
            {
                Console.WriteLine("Is Development ReportHostedService and TaskHostedService No Start!");
            }
            else
            {
                //本地式的消息压缩器
                context.Services.AddSingleton<IPasteCodeTaskBase, NoticeNotifyHandler>();
                context.Services.AddSingleton<IPasteCodeTaskBase, ReportHandler>();
                context.Services.AddSingleton<IPasteCodeTaskBase, CollectHandler>();
                context.Services.AddTransient<IPasteCodeTaskBase, RemoteTestHandler>();
                //TaskConfig:RunModel
                //var runmodel = Configuration.GetSection("TaskConfig:SingleModel").Value;
                context.Services.Configure<TaskNodeConfig>(Configuration.GetSection("TaskNodeConfig"));
                var singlemodel = Configuration.GetValue<Boolean>("TaskConfig:SingleModel");
                if (singlemodel)
                {
                    //单例模式
                    context.Services.AddSingleton<TaskChannelHelper>();
                    context.Services.AddScoped<TaskClientController>();
                }

                context.Services.AddTaskService();

                context.Services.AddHostedService<TaskLocalService>();
                context.Services.AddHostedService<SlaveHostedService>();

            }

        }

        /// <summary>
        /// 先加载配置信息
        /// </summary>
        /// <param name="context"></param>
        public override void PreConfigureServices(ServiceConfigurationContext context)
        {

            //Console.WriteLine("PasteTimerHttpApiHostModule.PreConfigureServices");

            #region 格式化日期的输出----------------------------------------------------------------------------------------------------


            context.Services.AddControllers().AddNewtonsoftJson(options =>
            {
                //日期格式化
                options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                //首字母小写
                options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
                //格式化显示
                options.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
                //忽略循环引用
                options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

                var dateConverter = new Newtonsoft.Json.Converters.IsoDateTimeConverter
                {
                    DateTimeFormat = "yyyy-MM-dd HH:mm:ss"
                };
                options.SerializerSettings.Converters.Add(dateConverter);
                options.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat;
            });
            Configure<MvcNewtonsoftJsonOptions>(options =>
            {
                options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";//对类型为DateTime的生效
                options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
                options.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;

            });

            //全局的默认配置
            Newtonsoft.Json.JsonSerializerSettings setting = new Newtonsoft.Json.JsonSerializerSettings();
            Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<Newtonsoft.Json.JsonSerializerSettings>(() =>
            {
                //日期格式化
                setting.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                //是否格式化换行便于阅读
                setting.Formatting = Newtonsoft.Json.Formatting.Indented;
                //首字母小写
                setting.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
                return setting;
            });

            //这个是对返回值序列号的格式转换
            Configure<AbpJsonOptions>(options =>
            {
                options.DefaultDateTimeFormat = "yyyy-MM-dd HH:mm:ss";
                options.UseHybridSerializer = false;//使用newtonsoft代替system.text.json？
            });  //对类型为DateTimeOffset生效

            #endregion ==============================================================================================================================

            context.Services.Configure<AbpJsonOptions>(options =>
            {
                options.DefaultDateTimeFormat = "yyyy-MM-dd HH:mm:ss";
                options.UseHybridSerializer = false;//使用newtonsoft代替system.text.json？
            });

            base.PreConfigureServices(context);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        public override void OnApplicationInitialization(ApplicationInitializationContext context)
        {

            var app = context.GetApplicationBuilder();
            var env = context.GetEnvironment();

            //app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseRouting();
            app.UseCors(DefaultCorsPolicyName);
            app.UseSwagger();

            app.UseAbpSwaggerUI(options =>
            {
                options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support APP API");
            });

            app.UseConfiguredEndpoints();
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class DateTimeJsonConverter : JsonConverter<DateTime>
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="typeToConvert"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            return DateTime.Parse(reader.GetString());
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="value"></param>
        /// <param name="options"></param>
        public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss"));
        }
    }


}
